using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;

namespace Catastrophe.Common.ObjM
{
	public class EmitUtil
	{
		public static Action<object, object> CreateSetter(PropertyInfo property)
		{
			if (property == null)
			{
				throw new ArgumentNullException("property");
			}
			if (!property.CanWrite)
			{
				return null;
			}
			MethodInfo setMethod = property.GetSetMethod(nonPublic: true);
			DynamicMethod dynamicMethod = new DynamicMethod("PropertySetter", null, new Type[2]
			{
				typeof(object),
				typeof(object)
			}, property.DeclaringType ?? throw new InvalidOperationException(), skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!setMethod.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
			}
			iLGenerator.Emit(OpCodes.Ldarg_1);
			EmitUtil.EmitCastToReference(iLGenerator, property.PropertyType);
			if (!setMethod.IsStatic && !property.DeclaringType!.IsValueType)
			{
				iLGenerator.EmitCall(OpCodes.Callvirt, setMethod, null);
			}
			else
			{
				iLGenerator.EmitCall(OpCodes.Call, setMethod, null);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (Action<object, object>)dynamicMethod.CreateDelegate(typeof(Action<object, object>));
		}

		public static Func<object, object> CreateGetter(PropertyInfo property)
		{
			if (property == null)
			{
				throw new ArgumentNullException("property");
			}
			MethodInfo getMethod = property.GetGetMethod(nonPublic: true);
			DynamicMethod dynamicMethod = new DynamicMethod("PropertyGetter", typeof(object), new Type[1] { typeof(object) }, property.DeclaringType ?? throw new InvalidOperationException(), skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!getMethod.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.EmitCall(OpCodes.Callvirt, getMethod, null);
			}
			else
			{
				iLGenerator.EmitCall(OpCodes.Call, getMethod, null);
			}
			if (property.PropertyType.IsValueType)
			{
				iLGenerator.Emit(OpCodes.Box, property.PropertyType);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (Func<object, object>)dynamicMethod.CreateDelegate(typeof(Func<object, object>));
		}

		private static void EmitCastToReference(ILGenerator il, Type type)
		{
			if (type.IsValueType)
			{
				il.Emit(OpCodes.Unbox_Any, type);
			}
			else
			{
				il.Emit(OpCodes.Castclass, type);
			}
		}

		public static T CreateInstance<T>()
		{
			Type typeFromHandle = typeof(T);
			ConstructorInfo constructor = typeFromHandle.GetConstructor(new Type[0]);
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(1, 1);
			defaultInterpolatedStringHandler.AppendLiteral("_");
			defaultInterpolatedStringHandler.AppendFormatted(Guid.NewGuid(), "N");
			DynamicMethod dynamicMethod = new DynamicMethod(defaultInterpolatedStringHandler.ToStringAndClear(), typeFromHandle, null);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			iLGenerator.Emit(OpCodes.Newobj, constructor);
			iLGenerator.Emit(OpCodes.Ret);
			Func<T> func = dynamicMethod.CreateDelegate(typeof(Func<T>)) as Func<T>;
			if (func != null)
			{
				return func();
			}
			return default(T);
		}

		public static object CreateInstance(Type type)
		{
			ConstructorInfo constructor = type.GetConstructor(new Type[0]);
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(1, 1);
			defaultInterpolatedStringHandler.AppendLiteral("_");
			defaultInterpolatedStringHandler.AppendFormatted(Guid.NewGuid(), "N");
			DynamicMethod dynamicMethod = new DynamicMethod(defaultInterpolatedStringHandler.ToStringAndClear(), type, null);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			iLGenerator.Emit(OpCodes.Newobj, constructor);
			iLGenerator.Emit(OpCodes.Ret);
			return (dynamicMethod.CreateDelegate(typeof(Func<object>)) as Func<object>)?.Invoke();
		}
	}
}
